//
//  PLCAudioRecorderHelper.m
//  PLCAudioRecorderDemo
//
//  Created by PlutusCat on 2017/4/27.
//  Copyright © 2017年 PlutusCat. All rights reserved.
//

#import "PLCAudioRecorderHelper.h"
#import <AVFoundation/AVFoundation.h>
#import "PLCAudioPath.h"
#import <lame/lame.h>
#import "XBAudioTool.h"

@interface PLCAudioRecorderHelper ()<AVAudioRecorderDelegate>
/** 录音文件地址 */
@property (nonatomic, strong) NSURL *recordFileUrl;
//音频录音机
@property (nonatomic, strong) AVAudioRecorder *audioRecorder;
@property (nonatomic, strong) AVAudioSession *session;
@property (nonatomic, strong) NSTimer * timer;

@end

@implementation PLCAudioRecorderHelper

static PLCAudioRecorderHelper *_instance;

static id instance;

+ (instancetype)sharedPLCAudioRecorderHelper {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (instance == nil) {
            instance = [[self alloc] init];
        }
    });
    return instance;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (instance == nil) {
            instance = [super allocWithZone:zone];
        }
    });
    return instance;
}

/**
 *  取得录音文件设置
 *
 *  @return 录音设置
 */
- (NSDictionary *)getAudioSetting {
    NSMutableDictionary *dicM = [NSMutableDictionary dictionary];

    [dicM setObject:@(kAudioFormatLinearPCM) forKey:AVFormatIDKey];
    [dicM setObject:@(11025.0) forKey:AVSampleRateKey];
    [dicM setObject:@(2) forKey:AVNumberOfChannelsKey];
    [dicM setObject:@(16) forKey:AVLinearPCMBitDepthKey];
    [dicM setObject:[NSNumber numberWithInt:AVAudioQualityHigh] forKey:AVEncoderAudioQualityKey];

    return dicM;
}


#pragma mark - - 开始录音
- (BOOL)startAudioRecorder {
    // 权限检测
    if (![PLCAudioRecorderHelper didSystemOpendMicrophone]) {
                
        UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:@"需要开启麦克风权限，请前往设置打开" preferredStyle:UIAlertControllerStyleAlert];
        [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:nil]];
        [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alert animated:YES completion:nil];
        
        return NO;
    }

    // 录音器设置
    if (_audioRecorder){
        if (_audioRecorder.isRecording){
            [_audioRecorder stop];
        }
        _audioRecorder = nil;
    }
    _recordFileUrl = [PLCAudioPath genernalRecordFilePath];
    NSDictionary *setting = [self getAudioSetting];
    NSError *error = nil;
    _audioRecorder = [[AVAudioRecorder alloc] initWithURL:_recordFileUrl settings:setting error:&error];
    _audioRecorder.delegate = self;
    _audioRecorder.meteringEnabled = YES;
    if (error) {
        NSLog(@"创建录音机对象时发生错误，错误信息：%@",error.localizedDescription);
        return nil;
    }
    [_audioRecorder prepareToRecord];
    
     // 设置音频会话
    if (!_session) {
        AVAudioSession *session = [AVAudioSession sharedInstance];
        NSError *sessionError;
        [session setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];
        
        if(session == nil) {
            NSLog(@"Error creating session: %@", [sessionError description]);
            return NO;
        }else {
            [session setActive:YES error:&sessionError];
            if (sessionError){
                NSLog(@"Error setActive session: %@", [sessionError description]);
            }
        }
        
        self.session = session;
    }
    
    // 开始录音
    [self.audioRecorder record];
    
    // 开启Timer 获取声音振幅
    if (self.peakPower){
        self.audioRecorder.meteringEnabled = YES;
        [self timerStart];
    }
    
    NSLog(@"timerAction timer start");
    
    return YES;
}

-(void)timerStart{
    if (!self.timer){
        self.timer = [NSTimer timerWithTimeInterval:0.2 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
    }
}

-(void)timerAction{
//    NSLog(@"timerAction timer action");
    if (self.peakPowerBlock){
        [self.audioRecorder updateMeters];
        // 静音为 -160 高峰为 0
        CGFloat peakPower = [self.audioRecorder peakPowerForChannel:0];
        NSInteger peak = 3 * (peakPower + 160) / 4;
//        NSLog(@"timerAction timer action %f %l",peakPower,peak);
        self.peakPowerBlock(@(peak));
    }
}

-(void)timerStop{
    NSLog(@"timerAction timer stop");
    if (self.timer){
        [self.timer invalidate];
        self.timer = nil;
    }
}

#pragma mark - - 暂停录音
- (void)pauseAudioRecorder {
    if ([self.audioRecorder isRecording]) {
        [self.audioRecorder pause];
    }
    [self timerStop];
}

#pragma mark - - 恢复录音
- (void)resumeAudioRecorder {
    [self startAudioRecorder];
    [self timerStart];
}

#pragma mark - - 停止录音
- (void)endAudioRecorder {
//    NSLog(@"timerAction timer endAudioRecorder");
    [self timerStop];
    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayback error:nil];  //此处需要恢复设置回放标志，否则会导致其它播放声音也会变小
    [self.audioRecorder stop];
    self.session = nil;
    [PLCAudioPath deleteInvalidRecordFile];
}

- (void)endAudioRecorderWithTranscodingBlock:(void(^)(NSString *))complete{
    [self timerStop];
    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayback error:nil];  //此处需要恢复设置回放标志，否则会导致其它播放声音也会变小
    [self.audioRecorder stop];
    self.session = nil;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self cafChangeToMP3WithPath:_recordFileUrl.path complete:complete];
    });
    [PLCAudioPath deleteInvalidRecordFile];
}

#pragma mark - - AVAudioRecorderDelegate -
/**
 *  录音完成，录音完成后播放录音
 *
 *  @param recorder 录音机对象
 *  @param flag     是否成功
 */
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag {
    if (flag) {
        NSLog(@"录音完成!");
//        [self.session setActive:NO error:nil];
        
//        [PLCAudioPath getRecordAttributes];
        
//        [recorder deleteRecording];
        
    }  
}

- (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError * __nullable)error {
    
    NSLog(@"录音出错 = %@", error);
}


#pragma mark - 后台是否允许app使用麦克风  YES——允许  NO——不允许
+ (BOOL)didSystemOpendMicrophone {
    
    if ([[AVAudioSession sharedInstance] respondsToSelector:@selector(requestRecordPermission:)]) {
        
        __block BOOL isEnable = YES;
        
        [[AVAudioSession sharedInstance] performSelector:@selector(requestRecordPermission:) withObject:^(BOOL granted) {
            if (granted) {
                // Microphone enabled code
                NSLog(@"Microphone is enabled..");
                isEnable = YES;
            }
            else {
                // Microphone disabled code
                NSLog(@"Microphone is disabled..");
                isEnable = NO;
            }
        }];
        
        return isEnable;
        
    }
    return NO;
}

#pragma mark - - caf 转换 mp3
- (void)cafChangeToMP3WithPath:(NSString *)path complete:(void(^)(NSString *))complete{
    
//    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSInteger fileSize = [PLCAudioPath getFileSizeWithPath:path];
    if (fileSize < 5*1240) {
        NSLog(@"录音文件无效。%@", path);
        complete(nil);
        return;
    }
    NSString *mp3FilePath = [PLCAudioPath getMp3RecordFileWithPath:path].path;
    @try {
        int read, write;
        FILE *pcm = fopen([path cStringUsingEncoding:1], "rb");  //source 被转换的音频文件位置
        fseek(pcm, 4*1024, SEEK_CUR);                                   //skip file header
        FILE *mp3 = fopen([mp3FilePath cStringUsingEncoding:1], "wb");  //output 输出生成的Mp3文件位置
        
        const int PCM_SIZE = 8192;
        const int MP3_SIZE = 8192;
        short int pcm_buffer[PCM_SIZE*2];
        unsigned char mp3_buffer[MP3_SIZE];
        
        //这里要注意，lame的配置要跟AVAudioRecorder的配置一致，否则会造成转换不成功
        lame_t lame = lame_init();
        lame_set_num_channels(lame,1);//设置1为单通道，默认为2双通道
        lame_set_in_samplerate(lame, 11025.0);
        lame_set_quality(lame,2);/* 2=high  5 = medium  7=low */
        lame_set_VBR_mean_bitrate_kbps(lame, 16);
        lame_init_params(lame);

        do {
            read = (int)fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
            if (read == 0)
                write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
            else
                write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);

            fwrite(mp3_buffer, write, 1, mp3);

        } while (read != 0);

        lame_close(lame);
        fclose(mp3);
        fclose(pcm);
        NSLog(@"MP3生成成功: %@", mp3FilePath);
        if (complete){
            if ([path isEqualToString:_recordFileUrl.path]){
                complete(mp3FilePath);
            }else{
                complete(nil);
            }
        }
    }
    @catch (NSException *exception) {
        NSLog(@"%@",[exception description]);
        [XBAudioTool log:XBAudioLogLevelError message:@"录音无效" parameters:@{@"desc": [exception description] ?: @"" }];
        if (complete){
            complete(nil);
        }
    }
    @finally {
        NSLog(@"结束: %@", mp3FilePath);
    }

//    });

}

@end
